package routower

import (
	"errors"
	"go.uber.org/zap"
	"sync"
	"wzgames/internal/gloader"
	"wzgames/internal/model/gamep"
	"wzgames/pkg/actor/actorservice"
	"wzgames/pkg/logger"
	"wzgames/pkg/remote/etcd"
)

// 新轮盘播报实例管理

var (
	instMgr  *InstManager
	onceInst sync.Once
)

type InstManager struct {
	mu sync.RWMutex

	instants map[int64]*RouManager
}

func InitInstManager() *InstManager {
	if instMgr == nil {
		onceInst.Do(func() {
			instMgr = &InstManager{
				instants: make(map[int64]*RouManager),
			}
		})
	}
	return instMgr
}

// OnInstChange 监控新轮盘实例配置变更
func (st *InstManager) OnInstChange(instId int64, evt etcd.KvEvtType) {
	switch evt {
	case etcd.KvEventNew:
		gmInst := gloader.GameMgr().GetGameInst(instId)
		if gmInst == nil {
			logger.Error("[RouTower] init new game instance fail on GetGameInst", zap.Int64("InstID", instId))
		} else {
			err := st.InitInst(gmInst)
			if err != nil {
				logger.Error("[RouTower] init new game instance fail on InitInst", zap.Int64("InstID", instId))
				return
			}
			inst := st.GetInst(gmInst.InstID)
			if inst != nil {
				actorservice.Send(inst.Pid(), StartRoulette{})
			}
		}
	case etcd.KvEventUpdate:
		st.mu.RLock()
		inst, ok := st.instants[instId]
		st.mu.RUnlock()
		if ok {
			inst.Update(gloader.GameMgr().GetGameInst(instId))
		}
	case etcd.KvEventDelete:
	}
}

func (st *InstManager) InitInst(inst *gamep.GameInst) error {
	st.mu.Lock()
	defer st.mu.Unlock()
	if _, ok := st.instants[inst.InstID]; ok {
		return errors.New("game instant already init")
	}
	st.instants[inst.InstID] = NewRouManager(inst)

	return nil
}

func (st *InstManager) GetInst(instId int64) *RouManager {
	st.mu.RLock()
	v, ok := st.instants[instId]
	st.mu.RUnlock()
	if ok {
		return v
	}

	return nil
}

// StartInstants 启动实例播报
func (st *InstManager) StartInstants() {
	st.mu.RLock()
	defer st.mu.RUnlock()
	for _, am := range st.instants {
		actorservice.Send(am.Pid(), StartRoulette{})
	}
}

func (st *InstManager) Destroy() {
	st.mu.Lock()
	defer st.mu.Unlock()
	for _, v := range st.instants {
		v.Destroy()
	}
}
